﻿#pragma once

#include <thread>
#include <atomic>
#include <memory>
#include <chrono>
#include "Framework/ApplicationSubsystem.h"
#include "RenderContext.m.h"

class CRenderSurface;
class CAllPreRenderData;

//管理由主线程控制的渲染数据
//并在预处理线程中进行预处理
RCLASS()
class WHENGINE_API RRenderContext : public RApplicationSubsystem
{
    ROBJECT
public:
    void Initialize() override;
    void Deinitialize() override;

    static RRenderContext* Get();

    struct SBufferReadWriteState
    {
        //是否可写
        std::atomic<bool> bWritable=true;
        
        //是否可读
        std::atomic<bool> bReadable=false;
    };

    //两个渲染数据缓冲区的状态
    //缓冲区数据由主线程写入/销毁，预处理线程仅读取
    //初始状态下，主线程从第一个缓冲区写入，预处理线程等待
    struct SRenderDataBuffersState
    {
        SBufferReadWriteState ReadWriteStates[2];

        //上一次读取的缓冲区索引，仅有预处理线程访问，不需要原子操作
        int8_t LastReadBufferIndex=-1;

        //上一次写入的缓冲区索引，仅有主线程访问，不需要原子操作
        int8_t LastWriteBufferIndex=-1;
    };

    SRenderDataBuffersState RenderDataBuffersState;

    //current render data buffer
    //only render thread can read/write it
    uint8_t CurrentReadBufferIndex=1;

    //current prepare data buffer
    //only main thread can read/write it
    uint8_t CurrentWriteBufferIndex=0;

    //找到一个可读取的缓冲区
    //这个函数仅供预处理线程调用
    //如果没有缓冲区准备好读取，返回false
    bool OccupyReadableBuffer()
    {
        if(RenderDataBuffersState.LastReadBufferIndex==1)
        {
            if(RenderDataBuffersState.ReadWriteStates[0].bReadable)
            {
                CurrentReadBufferIndex=0;
                return true;
            }
            else
            {
                CurrentReadBufferIndex=-1;
                return false;
            }
        }
        else if(RenderDataBuffersState.LastReadBufferIndex==0)
        {
            if(RenderDataBuffersState.ReadWriteStates[1].bReadable)
            {
                CurrentReadBufferIndex=1;
                return true;
            }
            else
            {
                CurrentReadBufferIndex=-1;
                return false;
            }
        }
        else
        {
            //第一次读取，尝试读取第一个缓冲区
            if(RenderDataBuffersState.ReadWriteStates[0].bReadable)
            {
                CurrentReadBufferIndex=0;
                return true;
            }
            else
            {
                CurrentReadBufferIndex=-1;
                return false;
            }
        }
    }

    //占据一个可写入的缓冲区
    //如果没有缓冲区可写入，返回false
    bool OccupyWritableBuffer()
    {
        if(RenderDataBuffersState.LastWriteBufferIndex==1)
        {
            if(RenderDataBuffersState.ReadWriteStates[0].bWritable)
            {
                CurrentWriteBufferIndex=0;
                return true;
            }
            else
            {
                CurrentWriteBufferIndex=-1;
                return false;
            }
        }
        else if(RenderDataBuffersState.LastWriteBufferIndex==0)
        {
            if(RenderDataBuffersState.ReadWriteStates[1].bWritable)
            {
                CurrentWriteBufferIndex=1;
                return true;
            }
            else
            {
                CurrentWriteBufferIndex=-1;
                return false;
            }
        }
        else
        {
            //第一次写入
            CurrentWriteBufferIndex=0;
            return true;
        }
    }

    //invoked by main thread
    //notify render thread that main thread has finished writing render data to buffer
    void ReleaseOccupiedWritingBuffer()
    {
        RenderDataBuffersState.LastWriteBufferIndex=CurrentWriteBufferIndex;
        RenderDataBuffersState.ReadWriteStates[CurrentWriteBufferIndex].bWritable=false;
        RenderDataBuffersState.ReadWriteStates[CurrentWriteBufferIndex].bReadable=true;
    }

    //invoked by render thread
    //notify main thread that render thread has finished reading render data from buffer
    void ReleaseOccupiedReadingBuffer()
    {
        RenderDataBuffersState.LastReadBufferIndex=CurrentReadBufferIndex;
        RenderDataBuffersState.ReadWriteStates[CurrentReadBufferIndex].bReadable=false;
        RenderDataBuffersState.ReadWriteStates[CurrentReadBufferIndex].bWritable=true;
    }


    //主线程写入渲染数据
    void WriteSurfaces(const TVector<std::shared_ptr<CRenderSurface>>& InSurfaces);
    TVector<std::shared_ptr<CRenderSurface>> ReadSurfaces();


    //预处理结果，由预处理线程写入，渲染线程读取
    //渲染线程读取后，会将PreProcessResult置为nullptr，以便继续接收新的预处理结果
    std::atomic<CAllPreRenderData*> PreProcessResult;

protected:
    //由主线程写入的窗口，预处理线程读取
    TVector<std::shared_ptr<CRenderSurface>> Surfaces[2];

    std::thread* PreProcessThread=nullptr;
    void PreProcessThreadRun();
    void PreRender(const TVector<std::shared_ptr<CRenderSurface>>& InSurfaces);


public:
    float GetRenderFramePerSecond() const
    {
        return RenderFramePerSecond.load();
    }

    //设置渲染线程帧率限制，0表示不限制
    void SetFrameLimit(bool InFrameLimit)
    {
        FrameLimit=InFrameLimit;
    }
protected:
    //上一次渲染结束的时间
    std::chrono::time_point<std::chrono::high_resolution_clock> 
        LastRenderTime=std::chrono::high_resolution_clock::now();
    
    //渲染线程帧率
    std::atomic<float> RenderFramePerSecond=0.0f;

    //渲染线程帧率限制
    std::atomic<float> FrameLimit=60;

};